package org.wu.framework.core.utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 电脑唯一标识符获取工具类
 * 综合多个硬件信息生成唯一标识符，提高唯一性可靠性
 * 静态方法内部处理异常，不向外抛出
 */
public class ComputerUniqueIdUtil {
    private static final Logger logger = Logger.getLogger(ComputerUniqueIdUtil.class.getName());

    // 支持的操作系统类型
    public enum OS {
        WINDOWS, MAC, LINUX, UNKNOWN
    }

    public static void main(String[] args) {
        // 获取操作系统类型
        OS osType = getOperatingSystem();
        System.out.println("操作系统: " + osType);

        // 获取单个硬件信息
        String motherboardSerial = getMotherboardSerialNumber();
        System.out.println("主板序列号: " + (motherboardSerial.isEmpty() ? "无法获取" : motherboardSerial));

        String diskSerial = getPrimaryDiskSerialNumber();
        System.out.println("硬盘序列号: " + (diskSerial.isEmpty() ? "无法获取" : diskSerial));

        String cpuId = getCpuId();
        System.out.println("CPU ID: " + (cpuId.isEmpty() ? "无法获取" : cpuId));

        // 生成综合唯一标识符
        String uniqueId = generateUniqueId();
        System.out.println("\n综合唯一标识符: " + (uniqueId.isEmpty() ? "生成失败" : uniqueId));
    }

    /**
     * 获取操作系统类型
     */
    public static OS getOperatingSystem() {
        try {
            String osName = System.getProperty("os.name").toLowerCase();
            if (osName.contains("win")) {
                return OS.WINDOWS;
            } else if (osName.contains("mac")) {
                return OS.MAC;
            } else if (osName.contains("nix") || osName.contains("nux") || osName.contains("aix")) {
                return OS.LINUX;
            } else {
                return OS.UNKNOWN;
            }
        } catch (SecurityException e) {
            logger.log(Level.SEVERE, "获取操作系统信息时发生安全异常", e);
            return OS.UNKNOWN;
        }
    }

    /**
     * 生成综合唯一标识符
     * 结合多个硬件信息并进行MD5加密，提高唯一性和安全性
     */
    public static String generateUniqueId() {
        List<String> hardwareInfos = new ArrayList<>();

        // 收集多个硬件信息作为基础
        hardwareInfos.add(getMotherboardSerialNumber());
        hardwareInfos.add(getPrimaryDiskSerialNumber());
        hardwareInfos.add(getCpuId());

        // 拼接所有信息
        StringBuilder infoBuilder = new StringBuilder();
        for (String info : hardwareInfos) {
            infoBuilder.append(info).append("|");
        }

        // 对拼接结果进行MD5加密，得到固定长度的唯一标识符
        try {
            return md5Encrypt(infoBuilder.toString());
        } catch (NoSuchAlgorithmException e) {
            logger.log(Level.SEVERE, "MD5加密失败", e);
            return "";
        }
    }

    /**
     * 获取主板序列号
     */
    public static String getMotherboardSerialNumber() {
        OS os = getOperatingSystem();
        String result = "";

        try {
            switch (os) {
                case WINDOWS:
                    result = executeCommand(List.of("wmic", "baseboard", "get", "serialnumber"));
                    result = extractValue(result, "SerialNumber");
                    break;
                case MAC:
                    result = executeCommand(List.of("ioreg", "-l", "|", "grep", "IOPlatformSerialNumber"));
                    result = extractMacSerial(result, "IOPlatformSerialNumber");
                    break;
                case LINUX:
                    // 尝试两种命令获取
                    result = executeCommand(List.of("sudo", "dmidecode", "-s", "system-serial-number"));
                    if (result.isEmpty() || result.contains("Not Applicable")) {
                        result = executeCommand(List.of("dmidecode", "-s", "system-serial-number"));
                    }
                    break;
                default:
                    result = "";
                    logger.warning("不支持的操作系统，无法获取主板序列号");
            }
        } catch (Exception e) {
            logger.log(Level.SEVERE, "获取主板序列号失败", e);
            result = "";
        }

        return result.trim();
    }

    /**
     * 获取主硬盘序列号
     */
    public static String getPrimaryDiskSerialNumber() {
        OS os = getOperatingSystem();
        String result = "";

        try {
            switch (os) {
                case WINDOWS:
                    result = executeCommand(List.of("wmic", "diskdrive", "where", "index=0", "get", "serialnumber"));
                    result = extractValue(result, "SerialNumber");
                    break;
                case MAC:
                    result = executeCommand(List.of("diskutil", "info", "/", "|", "grep", "Volume Serial Number"));
                    result = extractMacSerial(result, "Volume Serial Number");
                    break;
                case LINUX:
                    result = executeCommand(List.of("lsblk", "-n", "-o", "SERIAL", "/dev/sda"));
                    if (result.isEmpty()) {
                        result = executeCommand(List.of("lsblk", "-n", "-o", "SERIAL", "/dev/vda"));
                    }
                    break;
                default:
                    result = "";
                    logger.warning("不支持的操作系统，无法获取硬盘序列号");
            }
        } catch (Exception e) {
            logger.log(Level.SEVERE, "获取硬盘序列号失败", e);
            result = "";
        }

        return result.trim();
    }

    /**
     * 获取CPU ID
     */
    public static String getCpuId() {
        OS os = getOperatingSystem();
        String result = "";

        try {
            switch (os) {
                case WINDOWS:
                    result = executeCommand(List.of("wmic", "cpu", "get", "processorid"));
                    result = extractValue(result, "ProcessorId");
                    break;
                case MAC:
                    result = executeCommand(List.of("sysctl", "-n", "machdep.cpu.brand_string"));
                    break;
                case LINUX:
                    result = executeCommand(List.of("grep", "-m", "1", "^processor", "/proc/cpuinfo"));
                    if (result.isEmpty()) {
                        result = executeCommand(List.of("cat", "/proc/cpuinfo", "|", "grep", "model name", "|", "head", "-n", "1"));
                    }
                    break;
                default:
                    result = "";
                    logger.warning("不支持的操作系统，无法获取CPU ID");
            }
        } catch (Exception e) {
            logger.log(Level.SEVERE, "获取CPU ID失败", e);
            result = "";
        }

        return result.trim();
    }

    /**
     * 执行系统命令并返回输出结果
     * 使用ProcessBuilder替代已弃用的Runtime.exec()
     */
    private static String executeCommand(List<String> command) {
        try {
            // 创建ProcessBuilder并设置命令
            ProcessBuilder processBuilder = new ProcessBuilder(command);
            // 将错误流重定向到输入流，便于统一处理
            processBuilder.redirectErrorStream(true);

            // 启动进程
            Process process = processBuilder.start();

            // 读取命令输出
            try (InputStream inputStream = process.getInputStream();
                 BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {

                StringBuilder output = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    if (!line.trim().isEmpty()) {
                        output.append(line).append("\n");
                    }
                }

                // 等待命令执行完成
                int exitCode = process.waitFor();
                // 可以根据退出码判断命令是否执行成功
                if (exitCode != 0) {
                    logger.warning("命令执行失败，退出码: " + exitCode + ", 命令: " + command);
                }

                return output.toString();
            }
        } catch (IOException | InterruptedException e) {
            logger.log(Level.SEVERE, "执行命令失败: " + command, e);
            if (e instanceof InterruptedException) {
                Thread.currentThread().interrupt();
            }
            return "";
        }
    }

    /**
     * 提取命令输出中的值（针对Windows的wmic命令）
     */
    private static String extractValue(String output, String label) {
        if (output.isEmpty()) return "";

        String[] lines = output.split("\n");
        for (String line : lines) {
            if (line != null && !line.trim().equalsIgnoreCase(label) && !line.trim().isEmpty()) {
                return line.trim();
            }
        }
        return "";
    }

    /**
     * 提取Mac系统命令输出中的序列号
     */
    private static String extractMacSerial(String output, String label) {
        if (output.isEmpty()) return "";

        String[] lines = output.split("\n");
        for (String line : lines) {
            if (line != null && line.contains(label)) {
                String[] parts = line.split("=");
                if (parts.length > 1) {
                    return parts[1].trim().replace("\"", "");
                }
            }
        }
        return "";
    }

    /**
     * MD5加密
     */
    private static String md5Encrypt(String input) throws NoSuchAlgorithmException {
        if (input.isEmpty()) return "";

        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] messageDigest = md.digest(input.getBytes());

        // 转换为十六进制字符串
        StringBuilder hexString = new StringBuilder();
        for (byte b : messageDigest) {
            String hex = Integer.toHexString(0xFF & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }
}
    